--  ---------------------------------------------------------------------------
--  @File: file_tools.adb
--
--  @Project: LiberAda
--  @Version: 1.0
--  @Created: 2009-09-23
--  @Author:  Markus Knau�
--
--  @Description:
--    For a detailed description of this package (@see file_tools.ads).
--  @Implementation:
--    Composed file handling functions of base functions and additional checks.
--
--  @Modifications:
--    +2009-09-23 MK: Initial release
with Ada.Directories; use Ada.Directories;
with Ada.Containers.Vectors;
with Ada.Text_IO;

package body File_Tools is

   package ASU renames Ada.Strings.Unbounded;

   --  ------------------------------------------------------------------------
   --  @Package: Files
   --  @Purpose:
   --    Used for storing names of files and directories.
   package Files is new Ada.Containers.Vectors
     (Index_Type => Natural,
      Element_Type => ASU.Unbounded_String,
      "=" => ASU."=");

   --  ------------------------------------------------------------------------
   --  @Function: Is_Directory
   function Is_Directory (Name : in String) return Boolean is
   begin
      return Exists (Name) and then (Kind (Name) = Directory);
   end Is_Directory;

   --  ------------------------------------------------------------------------
   --  @Function: Is_File
   function Is_File (Name : in String) return Boolean is
   begin
      return Exists (Name) and then (Kind (Name) = Ordinary_File);
   end Is_File;

   --  ------------------------------------------------------------------------
   --  @Function: Files_In_Directory
   function Files_In_Directory
     (Directory : in String;
      Recurse   : in Boolean := False)
      return Files_Type is

      procedure Process_Directory
        (Dir_Entry : Directory_Entry_Type);

      --  ---------------------------------------------------------------------
      --  @Constant: EMPTY_FILES_ARRAY
      --  @Purpose:
      --    This constant value is returned if a directory contains no other
      --    files or directories.
      EMPTY_FILES_ARRAY : constant Files_Type (1 .. 1) :=
        (1 => ASU.Null_Unbounded_String);

      Files_Vector : Files.Vector;

      --  ---------------------------------------------------------------------
      --  @Procedure: Process_Directory
      --  @Description:
      --    This procedure recursively processes a directory by retrieving
      --    all files that are within this directory.
      --  @Parameter:
      --    +Dir_Entry: (@see Ada.Directories.Directory_Entry_Type)
      --  @Return:
      --    A list of all files that contained within a directory and,
      --    if the procedure works recursive, alle files in contained
      --    subdirectories.
      procedure Process_Directory (Dir_Entry : Directory_Entry_Type) is
      begin
         if Is_Directory (Full_Name (Dir_Entry)) and then
           Recurse and then
           Simple_Name (Dir_Entry) /= "." and then
           Simple_Name (Dir_Entry) /= ".."
         then
            Search (Directory => Full_Name (Dir_Entry), Pattern   => "",
              Process   => Process_Directory'Access);
         elsif Is_File (Full_Name (Dir_Entry)) then
            Files_Vector.Append (ASU.To_Unbounded_String (
              Full_Name (Dir_Entry)));
         end if;
      end Process_Directory;

   --  ------------------------------------------------------------------------
   begin
      if Is_Directory (Directory) then
         Search
           (Directory => Directory,
            Pattern   => "",
            Process   => Process_Directory'Access);
         if Integer (Files_Vector.Length) >= 1 then
            declare
               Files_Arr  : Files_Type (
                 Files_Vector.First_Index .. Files_Vector.Last_Index);
            begin
               for Files_Idx in Files_Arr'Range loop
                  Files_Arr (Files_Idx) := Files_Vector.Element (Files_Idx);
               end loop;
               Files_Vector.Clear;
               return Files_Arr;
            end;
         end if;
      end if;
      return EMPTY_FILES_ARRAY;
   end Files_In_Directory;

   --  -----------------------------------------------------------------------
   --  @Function: Extract_Filename
   function Extract_Filename
     (Path : in String;
      Include_Extension : Boolean := False;
      Ext_Divider       : String := "_")
      return String is

      use Ada.Text_IO;
      Filename : ASU.Unbounded_String;
      Last_Slash_Position : Natural;
      Slash_Found         : Boolean := False;
      Last_Point_Position : Natural;
      Point_Found         : Boolean := False;
   begin
      for Position in Path'Range loop
         --  Find last slash and last point in filepath
         if Path (Position) = '/' or Path (Position) = '\' then
            Last_Slash_Position := Position + 1;
            Slash_Found := True;
         end if;
         if Path (Position) = '.' then
            Last_Point_Position := Position - 1;
            Point_Found := True;
         end if;
         --  Cut the filename out of the path (from last slash to last point)
         if Slash_Found and Point_Found then
            Filename := ASU.To_Unbounded_String (ASU.Slice (
               ASU.To_Unbounded_String (Path), Last_Slash_Position,
               Last_Point_Position));
         elsif Slash_Found and not Point_Found then
            Filename := ASU.To_Unbounded_String (ASU.Slice (
               ASU.To_Unbounded_String (Path),
               Last_Slash_Position, Path'Last));
         elsif Point_Found and not Slash_Found then
            Filename := ASU.To_Unbounded_String (ASU.Slice (
               ASU.To_Unbounded_String (Path),
               Path'First, Last_Point_Position));
         end if;
         --  Add the extension to the filename (if existing)
         if Include_Extension and Point_Found then
            ASU.Append (Filename, Ext_Divider);
            ASU.Append (Filename, ASU.Slice (
               ASU.To_Unbounded_String (Path),
               Last_Point_Position + 2, Path'Last));
         end if;
      end loop;
      return ASU.To_String (Filename);
   end Extract_Filename;

   --  -----------------------------------------------------------------------
   --  @Function: Extract_Filename
   function Extract_Filename
     (Path : in Ada.Strings.Unbounded.Unbounded_String;
      Include_Extension : Boolean := False;
      Ext_Divider       : String := "_")

      return Ada.Strings.Unbounded.Unbounded_String is
   begin
      return Ada.Strings.Unbounded.To_Unbounded_String (Extract_Filename (
         Ada.Strings.Unbounded.To_String (Path),
         Include_Extension,
         Ext_Divider));
   end Extract_Filename;

end File_Tools;
